﻿(function($) {
    $.Mask = {
        /// <summary>Definition of regular expression</summary>
        Definitions: { '9': '[0-9]', 'a': '[A-Za-z]', '*': '[A-Za-z0-9]' },
        /// <summary>Definition of replace value</summary>
        ReplaceDefinitions: { 'x': '' },
        /// <summary>Definition of symbol for placeHolder char</summary>
        Holders: { 'all': '_' },
        /// <summary>Mask edit of control</summary>
        Maskes: {},
        /// <summary>Formula for create mask edit</summary>
        FormulaMaskes: {},
        /// <summary>Mask for replace value of control</summary>
        Replaces: {},
        /// <summary>First valid char into control</summary>
        FirstCharMasks: {},
        /// <summary>Indicates if ignored key</summary>
        IgnoredKeys: {}
    };

    $.Mask.Event = {
        OnFocus: function(e) {
            var $control = $(e.target);
            var id = $control.attr('id');

            if ($control.val() == '') {
                $control.val($.Mask.Maskes[id]);
            }

            $control.caret($.Mask.FirstCharMasks[id], $.Mask.FirstCharMasks[id]);
        },

        OnBlur: function(e) {
            var $control = $(e.target);
            if (!$.Mask.Functions.ValidateControl($control)) {
                $control.val('');
            }
        },

        OnKeyPress: function(e) {
            var $control = $(e.target);
            var id = $control.attr('id');

            if ($.Mask.IgnoredKeys[id]) {
                return false;
            }

            $.Mask.Functions.ShiftRigth($control, $control.caret().begin, String.fromCharCode(e.keyCode));
            return false;
        },

        OnKeyDown: function(e) {
            var $control = $(e.target);
            var id = $control.attr('id');

            if (e.keyCode >= 96 && e.keyCode <= 105) {
                e.keyCode -= 48;
            }

            if (e.keyCode != 8 && e.keyCode != 46) {
                $.Mask.IgnoredKeys[id] = !$.Mask.Functions.CheckChar($control.caret().begin, String.fromCharCode(e.keyCode), id).Validate;
            } else {
                var ck = $.Mask.Functions.CheckChar($control.caret().begin - 1, $.Mask.Holders[id], id);

                if (!ck.Validate && !ck.IsMask) {
                    return false;
                } else {
                    var pos = $control.caret().begin;
                    $.Mask.Functions.ShiftLeft($control, e.keyCode == 8 ? (pos - 1) : pos);
                    return false;
                }
            }
        }
    };

    $.Mask.Functions = {
        /// <summary>Validate data into control</summary>
        /// <param name="$control">TextBox control</param>
        /// <returns>Indicates if value is valid</returns>
        ValidateControl: function($control) {
            var text = $control.val();
            var id = $control.attr('id');
            var result = true;

            $.each($.Mask.Maskes[id], function(i) {
                if (!$.Mask.Functions.CheckChar(i, text.charAt(i), id).Validate) {
                    result = false;
                    return;
                }
            });

            return result;
        },

        /// <summary>Check if char is correct into position</summary>
        /// <param name="position">Position of new char</param>
        /// <param name="text">New text that insert into control</param>
        /// <param name="id">Code of control</param>
        /// <returns>
        ///     Validate : indicates if char is valid
        ///     IsMask : indicates if in position exist char mask
        /// </returns>
        CheckChar: function(position, text, id) {
            var c = $.Mask.Definitions[$.Mask.FormulaMaskes[id].charAt(position)];
            var isValidate;
            var isMask;

            if (c) {
                isValidate = new RegExp(c).test(text);
                isMask = true;
            } else {
                isValidate = ($.Mask.Maskes[id].charAt(position) == text);
                isMask = false;
            }

            return { Validate: isValidate, IsMask: isMask };
        },

        /// <summary>Shift char to right</summary>
        /// <param name="$control">Text box control</param>
        /// <param name="position">current position</param>
        /// <param name="text">text that insert for shift text</param>
        ShiftRigth: function($control, position, text) {
            var startText = $control.val();
            var id = $control.attr('id');
            var cursorposition = position + 1;
            var finalText = '';
            var tmpChar;

            for (var i = 0; i < startText.length; i++) {
                if (i < position) {
                    finalText += startText.charAt(i);
                } else if (i == position) {
                    finalText += text;
                    tmpChar = startText.charAt(i);

                    var ck = $.Mask.Functions.CheckChar(i + 1, startText.charAt(i + 1), id);
                    if (!ck.Validate && !ck.IsMask) {
                        cursorposition += 1;
                    }
                } else {
                    var ck = $.Mask.Functions.CheckChar(i, tmpChar, id);
                    if (ck.Validate || (!ck.Validate && !ck.IsMask)) {
                        if (!ck.Validate) {
                            finalText += startText.charAt(i);
                            tmpChar = startText.charAt(i + 1);
                        } else {
                            finalText += tmpChar;
                            tmpChar = startText.charAt(i);
                        }
                    } else {
                        if (ck.IsMask) {
                            finalText += startText.slice(i, startText.length);
                            break;
                        }
                    }
                }
            }

            $control.val(finalText).caret(cursorposition, cursorposition);
        },

        /// <summary>Shift char to left</summary>
        /// <param name="$control">Text box control</param>
        /// <param name="position">current position</param>
        /// <param name="text">text that insert for shift text</param>
        ShiftLeft: function($control, position) {
            var startText = $control.val();
            var id = $control.attr('id');
            var finalText = '';
            var indexCopy = -1;
            var tmpChar;

            for (var i = 0; i <= startText.length; i++) {
                if (i < position) {
                    finalText += startText.charAt(i);
                } else if (i == position) {
                    var ck = $.Mask.Functions.CheckChar(i, startText.charAt(i + 1), id);
                    if (!ck.Validate) {
                        if (ck.IsMask) {
                            finalText += $.Mask.Holders[id];
                            indexCopy = i + 1;
                            break;
                        } else {
                            finalText += startText.charAt(i);
                            indexCopy = i + 1;
                            break;
                        }
                    }
                } else {
                    if ($.Mask.Functions.CheckChar(position, startText.charAt(i), id).Validate) {
                        finalText += startText.charAt(i);
                    } else {
                        finalText += $.Mask.Holders[id];
                        indexCopy = i;
                        break;
                    }
                }
            }

            finalText += startText.slice(indexCopy, startText.length);
            $control.val(finalText).caret(position, position);
        }
    };

    $.fn.extend({
        /// <summary>Create Mask control</summary>
        /// <param name="maskText">Formula for create mask edit</param>
        /// <param name="attribute">
        ///     holder : char for placeHolder
        ///     replaceText : formula for replace text into control
        /// </param>
        mask: function(maskText, attributes) {
            var $control = $(this);
            var id = $control.attr('id');

            if (!attributes) {
                attributes = new Object();
            }

            $.Mask.Holders[id] = attributes.holder ? attributes.holder : $.Mask.Holders['all'];

            $control.bind('blur', $.Mask.Event.OnBlur);
            $control.bind('focus', $.Mask.Event.OnFocus);
            $control.bind('keypress', $.Mask.Event.OnKeyPress);
            $control.bind('keydown', $.Mask.Event.OnKeyDown);

            var ms = '';
            var firstCharMask = -1;

            $.each(maskText, function(i) {
                var c = $.Mask.Definitions[maskText.charAt(i)];

                if (c) {
                    ms += $.Mask.Holders[id];

                    if (firstCharMask == -1) {
                        firstCharMask = i;
                    }
                } else {
                    ms += maskText.charAt(i);
                }
            });

            if (firstCharMask == -1) {
                firstCharMask = 0;
            }

            $.Mask.FormulaMaskes[id] = maskText;
            $.Mask.Maskes[id] = ms;
            $.Mask.FirstCharMasks[id] = firstCharMask;

            if (attributes.replaceText) {
                $.Mask.Replaces[id] = attributes.replaceText;
            }
        },

        /// <summary>Remove Mask Edit control</summary>
        unmask: function() {
            var $control = $(this);

            $control.unbind('blur', $.Mask.Event.OnBlur);
            $control.unbind('focus', $.Mask.Event.OnFocus);
            $control.unbind('keypress', $.Mask.Event.OnKeyPress);
            $control.unbind('keydown', $.Mask.Event.OnKeyDown);
        },

        /// <summary>Return text without edit mask</summary>
        getValueWithOutMask: function() {
            var $control = $(this);
            var id = $control.attr('id');
            var finalText = '';

            if ($.Mask.Replaces[id]) {
                var currentText = $control.val();

                for (var i = 0; i < $.Mask.Replaces[id].length; i++) {
                    var sub = $.Mask.ReplaceDefinitions[$.Mask.Replaces[id].charAt(i)];

                    finalText += (sub != undefined && sub != null) ? sub : currentText.charAt(i);
                }
            } else {
                finalText = $control.val();
            }

            return finalText;
        },

        /// <summary>Replace Text into control and remove Mask Edit</summary>
        replaceWithOutMask: function() {
            var $control = $(this);
            var text = $control.getValueWithOutMask();
            $control.unmask();
            $control.val(text.ReplaceString($.Mask.Holders[$control.attr('id')], ''));
        }
    });
})(jQuery);